1 module hip.graphics.g2d.renderer2d;
2 
3 version(Have_bindbc_lua) version = HipremeEngineLua;
4 
5 import hip.graphics.g2d.spritebatch;
6 import hip.graphics.g2d.tilemap;
7 import hip.graphics.g2d.geometrybatch;
8 import hip.graphics.orthocamera;
9 import hip.hiprenderer;
10 import hip.bind.interpreters;
11 public import hip.api.graphics.color;
12 public import hip.api.data.commons:IHipAssetLoadTask;
13 public import hip.graphics.g2d.textrenderer;
14 public import hip.api.renderer.viewport;
15 
16 public import hip.api.data.font;
17 
18 private __gshared
19 {
20     IHipTexture defaultTexture;
21     HipSpriteBatch spBatch;
22     GeometryBatch geoBatch;
23     HipTextRenderer textBatch;
24     HipOrthoCamera camera;
25     Viewport viewport;
26     HipTextRenderer textRenderer;
27     IHipBatch lastBatch;
28     bool autoUpdateCameraAndViewport;
29     float sharedDepth = 0;
30 }
31 
32 void manageBatchChange(IHipBatch newBatch)
33 {
34     if(lastBatch !is null && lastBatch !is newBatch)
35     {
36         sharedDepth+= 0.1;
37         lastBatch.draw();
38 
39         if(newBatch !is null)
40             newBatch.setCurrentDepth(sharedDepth);
41     }
42     lastBatch = newBatch;
43 }
44 
45 
46 import hip.console.log;
47 void initialize(HipInterpreterEntry entry = HipInterpreterEntry.init, bool shouldAutoUpdateCameraAndViewport = true)
48 {
49     autoUpdateCameraAndViewport = shouldAutoUpdateCameraAndViewport;
50     hiplog("2D Renderer: Initializing viewport");
51     viewport = new Viewport(0, 0, HipRenderer.width, HipRenderer.height);
52     viewport.setWorldSize(HipRenderer.width, HipRenderer.height);
53     viewport.setType(ViewportType.fit, HipRenderer.width, HipRenderer.height);
54     HipRenderer.setViewport(viewport);
55     hiplog("2D Renderer: Initializing camera");
56     camera = new HipOrthoCamera();
57     camera.setSize(viewport.worldWidth, viewport.worldHeight);
58 
59     hiplog("2D Renderer: Initializing spritebatch");
60     spBatch = new HipSpriteBatch(camera);
61     hiplog("2D Renderer: Initializing geometrybatch");
62     geoBatch = new GeometryBatch(camera);
63     hiplog("2D Renderer: Initializing text renderer");
64     textBatch = new HipTextRenderer(camera);
65     setGeometryColor(HipColor.white);
66 
67 
68     version(HipremeEngineLua)
69     {
70         hiplog("2D Renderer: sending lua functions");
71         if(entry != HipInterpreterEntry.init)
72         {
73             sendInterpreterFunc!(setGeometryColor)(entry.intepreter);
74             sendInterpreterFunc!(drawPixel)(entry.intepreter);
75             sendInterpreterFunc!(drawRectangle)(entry.intepreter);
76             sendInterpreterFunc!(drawTriangle)(entry.intepreter);
77             sendInterpreterFunc!(fillRectangle)(entry.intepreter);
78             sendInterpreterFunc!(fillEllipse)(entry.intepreter);
79             sendInterpreterFunc!(drawEllipse)(entry.intepreter);
80             sendInterpreterFunc!(fillTriangle)(entry.intepreter);
81             sendInterpreterFunc!(drawLine)(entry.intepreter);
82             sendInterpreterFunc!(drawQuadraticBezierLine)(entry.intepreter);
83             // sendInterpreterFunc!(drawText)(entry.intepreter); not supported yet
84         }
85     }
86 
87 }
88 
89 /**
90 *   This resizes both the 2D renderer viewport and its Orthographic Camera, maintaining always the
91 *   correct aspect ratio
92 */
93 void resizeRenderer2D(uint width, uint height)
94 {
95     if(autoUpdateCameraAndViewport)
96     {
97         if(viewport !is null && HipRenderer.getCurrentViewport() == viewport)
98             HipRenderer.setViewport(viewport);
99         if(camera !is null)
100             camera.setSize(viewport.worldWidth, viewport.worldHeight);
101     }
102 }
103 
104 export extern(System):
105 
106 
107 int[2] getWindowSize(){return [HipRenderer.width, HipRenderer.height];}
108 
109 void setWindowSize(uint width, uint height)
110 {
111     HipRenderer.setWindowSize(width, height);
112     HipRenderer.setViewport(viewport);
113     camera.setSize(cast(int)viewport.worldWidth,cast(int)viewport.worldHeight);
114 }
115 void setCameraSize(uint width, uint height){camera.setSize(width, height);}
116 void setViewport(Viewport v)
117 {
118     HipRenderer.setViewport(v);
119 }
120 void setStencilTestingEnabled(bool bEnable)
121 {
122     manageBatchChange(null);
123     HipRenderer.setStencilTestingEnabled(bEnable);
124 }
125 void setStencilTestingMask(uint mask)
126 {
127     manageBatchChange(null);
128     HipRenderer.setStencilTestingMask(mask);
129 }
130 void setRendererColorMask(ubyte r, ubyte g, ubyte b, ubyte a)
131 {
132     manageBatchChange(null);
133     HipRenderer.setColorMask(r,g,b,a);
134 }
135 void setStencilTestingFunction(HipStencilTestingFunction passFunc, uint reference, uint mask)
136 {
137     manageBatchChange(null);
138     HipRenderer.setStencilTestingFunction(passFunc, reference, mask);
139 }
140 void setStencilOperation(HipStencilOperation stencilFail, HipStencilOperation depthFail, HipStencilOperation stencilAndDephPass)
141 {
142     manageBatchChange(null);
143     HipRenderer.setStencilOperation(stencilFail, depthFail, stencilAndDephPass);
144 }
145 Viewport getCurrentViewport()
146 {
147     import hip.util.lifetime;
148     return cast(typeof(return))hipSaveRef(HipRenderer.getCurrentViewport());
149 }
150 
151 void setRendererErrorCheckingEnabled(bool enable)
152 {
153     HipRenderer.setErrorCheckingEnabled(enable);
154 }
155 void setGeometryColor(const HipColor color){geoBatch.setColor(color);}
156 void drawPixel(int x, int y, HipColor color = HipColor.no)
157 {
158     manageBatchChange(geoBatch);
159     geoBatch.drawPixel(x, y,color);
160 }
161 void drawRectangle(int x, int y, int w, int h, HipColor color = HipColor.no)
162 {
163     manageBatchChange(geoBatch);
164     geoBatch.drawRectangle(x,y,w,h,color);
165 }
166 void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, HipColor color = HipColor.no)
167 {
168     manageBatchChange(geoBatch);
169     geoBatch.drawTriangle(x1,y1,x2,y2,x3,y3,color);
170 }
171 void drawEllipse(int x, int y, int radiusW, int radiusH, int degrees = 360, HipColor color = HipColor.no, int precision = 24)
172 {
173     manageBatchChange(geoBatch);
174     geoBatch.drawEllipse(x,y,radiusW,radiusH,degrees,color,precision);
175 }
176 void drawLine(int x1, int y1, int x2, int y2, HipColor color = HipColor.no)
177 {
178     manageBatchChange(geoBatch);
179     geoBatch.drawLine(x1,y1,x2,y2,color);
180 }
181 void drawQuadraticBezierLine(int x0, int y0, int x1, int y1, int x2, int y2, int precision=24, HipColor color = HipColor.no)
182 {
183     manageBatchChange(geoBatch);
184     geoBatch.drawQuadraticBezierLine(x0,y0,x1,y1,x2,y2,precision,color);
185 }
186 void fillRectangle(int x, int y, int w, int h, HipColor color = HipColor.no)
187 {
188     manageBatchChange(geoBatch);
189     geoBatch.fillRectangle(x,y,w,h,color);
190 }
191 void fillRoundRect(int x, int y, int w, int h, int radius = 4, HipColor color = HipColor.no, int precision = 16)
192 {
193     manageBatchChange(geoBatch);
194     geoBatch.fillRoundRect(x,y,w,h,radius, color, precision);
195 }
196 void fillEllipse(int x, int y, int radiusW, int radiusH = -1, int degrees = 360, HipColor color = HipColor.no, int precision = 24)
197 {
198     manageBatchChange(geoBatch);
199     geoBatch.fillEllipse(x,y,radiusW,radiusH,degrees,color,precision);
200 }
201 void fillTriangle(int x1, int y1, int x2,  int y2, int x3, int y3, HipColor color = HipColor.no)
202 {
203     manageBatchChange(geoBatch);
204     geoBatch.fillTriangle(x1,y1,x2,y2,x3,y3,color);
205 }
206 
207 void drawSprite(IHipTexture texture, ubyte[] vertices)
208 {
209     manageBatchChange(spBatch);
210     spBatch.draw(texture, vertices);
211 }
212 void drawRegion(IHipTextureRegion reg, int x, int y, int z = 0, const HipColor color = HipColor.white, float scaleX = 1, float scaleY = 1, float rotation = 0)
213 {
214     manageBatchChange(spBatch);
215     spBatch.draw(reg, x, y, z, color, scaleX, scaleY, rotation);
216 }
217 void drawMap(IHipTilemap map)
218 {
219     manageBatchChange(spBatch);
220     map.render(spBatch, false);
221 }
222 
223 void drawTexture(IHipTexture texture, int x, int y, int z = 0, const HipColor color = HipColor.white, float scaleX = 1, float scaleY = 1, float rotation = 0)
224 {
225     manageBatchChange(spBatch);
226     spBatch.draw(texture, x, y, z, color, scaleX, scaleY, rotation);
227 }
228 
229 
230 public import hip.util.data_structures : Array2D, Array2D_GC;
231 Array2D_GC!IHipTextureRegion cropSpritesheet(
232     IHipTexture t,
233     uint frameWidth, uint frameHeight,
234     uint width, uint height,
235     uint offsetX, uint offsetY,
236     uint offsetXPerFrame, uint offsetYPerFrame
237 )
238 {
239     import hip.assets.texture;
240     import hip.util.lifetime;
241     return cast(typeof(return))hipSaveRef(HipTextureRegion.cropSpritesheet(t, 
242         frameWidth, frameHeight, 
243         width, height, 
244         offsetX, offsetY, 
245         offsetXPerFrame, offsetYPerFrame
246     ).toGC());
247 }
248 
249 void setFont(IHipFont font)
250 {
251     import hip.global.gamedef;
252     if(font is null)
253         textBatch.setFont(cast(IHipFont)HipDefaultAssets.font);
254     else
255         textBatch.setFont(font);
256 }
257 void setFontDeferred(IHipAssetLoadTask task)
258 {
259     import hip.global.gamedef;
260     if(task is null)
261         textBatch.setFont(cast(IHipFont)HipDefaultAssets.font);
262     else
263         textBatch.setFont(task);
264 }
265 
266 void setTextColor(HipColor color)
267 {
268     manageBatchChange(textBatch);
269     textBatch.setColor(color);
270 }
271 void drawText(string text, int x, int y, HipColor color = HipColor.white, HipTextAlign alignH = HipTextAlign.LEFT, HipTextAlign alignV = HipTextAlign.CENTER, 
272 int boundsWidth = -1, int boundsHeight = -1, bool wordWrap = false)
273 {
274     manageBatchChange(textBatch);
275     textBatch.setColor(color);
276     textBatch.draw(text, x, y, alignH, alignV, boundsWidth, boundsHeight, wordWrap);
277 }
278 
279 void drawTextVertices(void[] vertices, IHipFont font)
280 {
281     manageBatchChange(textBatch);
282     textBatch.addVertices(vertices, font);
283 }
284 
285 Array2D_GC!IHipTextureRegion cropSpritesheetRowsAndColumns(IHipTexture t, uint rows, uint columns)
286 {
287     uint frameWidth = t.getWidth() / columns;
288     uint frameHeight = t.getHeight() / rows;
289     return cropSpritesheet(t,frameWidth,frameHeight, t.getWidth, t.getHeight, 0, 0, 0, 0);
290 }
291 
292 void finishRender2D()
293 {
294     if(geoBatch) geoBatch.flush();
295     if(spBatch) spBatch.flush();
296     if(textBatch) textBatch.flush();
297     lastBatch = null;
298     sharedDepth = 0;
299     if(geoBatch) geoBatch.setCurrentDepth(0);
300     if(spBatch) spBatch.setCurrentDepth(0);
301     if(textBatch) textBatch.setCurrentDepth(0);
302 }
303 
304 version(Standalone)
305 {
306     public import exportd;
307 }